package com.iwinding.ladygg.bluetooth.impBle;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothProfile;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.iwinding.ladygg.bluetooth.impblekit.ICaneBleApi;
import com.iwinding.ladygg.utils.ClsUtils;
import com.iwinding.ladygg.bluetooth.bean.BleDevice;
import com.iwinding.ladygg.bluetooth.ibluetooth.IAutoBlelimit;
import com.iwinding.ladygg.bluetooth.ibluetooth.IBleFunction;
import com.iwinding.ladygg.bluetooth.ibluetooth.IHandler;
import com.iwinding.ladygg.utils.HexStringUtil;
import com.iwinding.ladygg.utils.LogUtil;
import com.junkchen.blelib.BleService;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by 82218 on 2017/7/12.
 */

public class BleManager implements IBleFunction {

    private static final String TAG = BleManager.class.getSimpleName();

    /**
     * 内部类实现单例模式
     * 延迟加载，减少内存开销
     *
     * @author xuzhaohu
     */
    private static class SingletonHolder {
        private static BleManager instance = new BleManager();
    }

    public static BleManager getInstance() {
        return SingletonHolder.instance;
    }

    public BleManager() {
        mHandler = new BleHandler();
        deviceList = new ArrayList<BleDevice>();
        disConnList = new ArrayList<BleDevice>();
    }

    private Context mApplicationContext;
    private BleService bleService;
    private IAutoBlelimit autoLimit;
    private String SERVICE_NAME;
    private String SERVICE_FEATURES;

    private String mConnRssi;//当前连接设备信号
    private String connDeviceName;//当前连接设备名称
    private String connDeviceAddress;//当前连接设备地址
    private List<BleDevice> deviceList;//设备列表
    private List<BleDevice> disConnList;//断开连接的列表

    private BleHandler mHandler;

    private ServiceConnection serviceConnection;

    private BleReceiver bleReceiver;
    private BleService.OnLeScanListener onLeScanListener;
    private BleService.OnConnectionStateChangeListener onConnectionStateChangeListener;
    private BleService.OnServicesDiscoveredListener onServicesDiscoveredListener;
    private BleService.OnDataAvailableListener onDataAvailableListener;

    public List<BleDevice> getDeviceList() {
        return deviceList;
    }

    @Override
    public void initBle(Context application) {
        if (bleService != null) {
            closeBle();
        }
        mApplicationContext = application.getApplicationContext();

        serviceConnection = new BleServiceConnection();
        try {
            Intent serviceIntent = new Intent(mApplicationContext, BleService.class);
            mApplicationContext.bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
        } catch (Exception e) {
            Log.i(TAG, e.toString());
        }
    }

    @Override
    public void setAutoConnBle(IAutoBlelimit blelimit) {
        this.autoLimit = blelimit;
    }

    @Override
    public void openBle() {
        if (bleService == null) {
            Toast.makeText(mApplicationContext, "not support Bluetooth", Toast.LENGTH_SHORT).show();
            return;
        }
        LogUtil.i("@hzy", "openBle----------" + deviceList.size());
        if (bleService.enableBluetooth(true)) {
            LogUtil.i("@hzy", "openBle----------open");
            mHandler.sendEmptyMessage(SERVICE_OPEN);
        }
    }

    @Override
    public void scanBle() {
        if (bleService == null) {
            return;
        }
        LogUtil.i("@hzy", "scanBle----------" + deviceList.size());
        //监听扫描设备
        setBleReceiver();
        //清空设备表然后进行扫描
        deviceList.clear();
        disConnList.clear();
        bleService.scanLeDevice(true, SCAN_PERIOD);
    }

    private void setBleReceiver() {
        if (bleReceiver == null)
            bleReceiver = new BleReceiver(mHandler);
        mApplicationContext.registerReceiver(bleReceiver, BleReceiver.makeIntentFilter());

        if (onLeScanListener == null)
            onLeScanListener = new BleService.OnLeScanListener() {
                @Override
                public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
                    if (bleService == null) {
                        return;
                    }
                    BleDevice bleDevice = new BleDevice();
                    bleDevice.deviceName = device.getName();
                    bleDevice.deviceAddress = device.getAddress();
                    bleDevice.deviceRssi = String.valueOf(rssi);
                    bleDevice.isConnect = false;
                    LogUtil.i("@hzy", "scanBle----------add:" + bleDevice.deviceAddress);
                    deviceList.add(bleDevice);
                }
            };
        if (onConnectionStateChangeListener == null)
            onConnectionStateChangeListener = new BleService.OnConnectionStateChangeListener() {
                @Override
                public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
                    if (gatt == null) {
                        return;
                    }
                    final String address = gatt.getDevice().getAddress();
                    if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                        LogUtil.i("@hzy", "autoConnetBle----------" + connDeviceAddress + "----status:STATE_DISCONNECTED:");
                        LogUtil.i("@hzy", "autoConnetBle----------" + gatt.connect());
                        connDeviceAddress = "";
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                gatt.disconnect();
                                gatt.close();
                            }
                        });
                        for (BleDevice device : deviceList) {
                            if (TextUtils.equals(device.deviceAddress, address)) {
                                device.isConnect = false;
                                if (autoLimit != null && autoLimit.isNeedAutoConnect()) {
                                    disConnList.add(device);
                                    mHandler.sendEmptyMessage(CONNET_NEXT);
                                }
                            }
                        }
                        mHandler.sendEmptyMessage(DISCONNECTED);
                        if (deviceList.size() == disConnList.size()) {
                            mHandler.sendEmptyMessage(CLOSE_BLE);
                        }
                        //Ble连接已断开
                    } else if (newState == BluetoothProfile.STATE_CONNECTING) {
                        LogUtil.i("@hzy", "autoConnetBle----------" + connDeviceAddress + "----status:STATE_CONNECTING:");
                        //Ble正在连接
                    } else if (newState == BluetoothProfile.STATE_CONNECTED) {
                        LogUtil.i("@hzy", "autoConnetBle----------" + connDeviceAddress + "----status:STATE_CONNECTED:");
                        mHandler.sendEmptyMessage(CONNECTING);
                        //Ble已连接
                    } else if (newState == BluetoothProfile.STATE_DISCONNECTING) {
                        //Ble正在断开连接
                        LogUtil.i("@hzy", "autoConnetBle----------" + connDeviceAddress + "----status:STATE_DISCONNECTING:");
                    }
                }
            };
        if (onServicesDiscoveredListener == null) {
            onServicesDiscoveredListener = new BleService.OnServicesDiscoveredListener() {

                @Override
                public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                    LogUtil.i("@hzy", "onServicesDiscovered----------" + status);
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        connDeviceAddress = gatt.getDevice().getAddress();
                        for (BleDevice device : deviceList) {
                            if (TextUtils.equals(device.deviceAddress, connDeviceAddress)) {
                                device.isConnect = true;
                                if (autoLimit != null && autoLimit.isNeedAutoConnect()) {
                                    autoLimit.connDoSomethings(device, gatt);
                                }
                            }
                        }
                        mHandler.sendEmptyMessage(SERVICE_SHOW);
                    }
                }
            };
        }

        if (onDataAvailableListener == null)
            onDataAvailableListener = new BleService.OnDataAvailableListener() {
                @Override
                public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

                }

                @Override
                public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                    //处理通知返回的数据
                    byte[] value = characteristic.getValue();
                    Log.i("@hzy", "onCharacteristicChanged-----" + HexStringUtil.bytesToHexString(value));
                    ICaneBleApi.getInstance().analysis(value);
                }

                @Override
                public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {

                }
            };


        bleService.setOnLeScanListener(onLeScanListener);
        bleService.setOnConnectListener(onConnectionStateChangeListener);
        bleService.setOnServicesDiscoveredListener(onServicesDiscoveredListener);
        bleService.setOnDataAvailableListener(onDataAvailableListener);
        bleService.setOnMtuChangedListener(new BleService.OnMtuChangedListener() {

            @Override
            public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
                LogUtil.i("@hzy", "onMtuChanged----------" + gatt.getDevice().getAddress() + "------" + mtu + "------" + status);
            }
        });
    }

    @Override
    public void stopScanBle() {

    }

    @Override
    public void connetBle(final String address) {
        if (bleService == null) {
            return;
        }
        if (TextUtils.isEmpty(address)) {
            return;
        }
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                bleService.connect(address);
            }
        });

    }

    @Override
    public boolean isConnetBle() {
        return false;
    }

    @Override
    public void setPin(Class btClass, BluetoothDevice btDevice, String str) {
        try {
            ClsUtils.setPairingConfirmation(btDevice.getClass(), btDevice, true);
            ClsUtils.setPin(btClass, btDevice, str);
            ClsUtils.cancelPairingUserInput(btClass, btDevice);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setPin(String str) {
        if (bleService == null) {
            return;
        }
        BluetoothDevice device = bleService.getConnectDevice();
        if (device != null) {
//            device.setPin(ClsUtils.convertPinToBytes("123456"));
//            device.setPairingConfirmation(true);
            setPin(BluetoothDevice.class, device, str);
        }
    }


    @Override
    public void disConnetBle() {
        if (bleService == null) {
            return;
        }
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                bleService.disconnect();
            }
        });
    }

    @Override
    public void autoConnetBle() {
        if (autoLimit == null || !autoLimit.isNeedAutoConnect()) {
            return;
        }
        if (bleService == null) {
            return;
        }
        if (deviceList.size() == 0) {
            closeBle();
            return;
        }
        LogUtil.i("@hzy", "autoConnetBle----------" + deviceList.size());
        for (BleDevice device : deviceList) {
            if (!disConnList.contains(device)) {
                LogUtil.i("@hzy", "autoConnetBle----------" + device.deviceAddress);
                connetBle(device.deviceAddress);
            }
        }
    }

    @Override
    public String readRssi() {
        return null;
    }

    @Override
    public void setCharacteristic(BluetoothGattCharacteristic characteristic) {
        if (bleService == null) {
            return;
        }
        bleService.setCharacteristicNotification(characteristic, true);
    }

    @Override
    public void writeBle(String serviceUUID, String characteristicUUID, byte[] value) {
        if (bleService == null) {
            return;
        }
        bleService.writeCharacteristic(serviceUUID, characteristicUUID, value);
    }

    @Override
    public void closeBle() {
        if(bleService==null){
            return;
        }
        closeBleReceiver();
        bleService.disconnect();

        //解绑服务
        mApplicationContext.unbindService(serviceConnection);
        serviceConnection = null;
        bleService = null;

        if (autoLimit != null && autoLimit.isNeedAutoConnect())
            initBle(mApplicationContext);
    }

    private void closeBleReceiver() {
        mApplicationContext.unregisterReceiver(bleReceiver);
        bleReceiver = null;
        //解除监听
        bleService.setOnLeScanListener(null);
        bleService.setOnConnectListener(null);
        bleService.setOnServicesDiscoveredListener(null);
        bleService.setOnDataAvailableListener(null);
        onLeScanListener = null;
        onConnectionStateChangeListener = null;
        onServicesDiscoveredListener = null;
        onDataAvailableListener = null;
    }

    @Override
    public void register(IHandler i) {
        mHandler.register(i);
    }

    @Override
    public void unRegister(IHandler i) {
        mHandler.unRegister(i);
    }

    class BleServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            bleService = ((BleService.LocalBinder) service).getService();
            if (bleService.initialize()) {
                mHandler.sendEmptyMessage(SERVICE_BIND);
            } else {
                Toast.makeText(mApplicationContext, "not support Bluetooth", Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }


}
